/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "discover.h"

#include "common.h"
#include "discovery_service.h"
#include "ohos_bt_gap.h"
#include "softbus_bus_center.h"

#define MAX_CAP_NUM 9
#define DEFAULT_CAP_NUM 7

static sem_t g_publishSem;

bool __attribute__ ((weak)) GetLocalAddr(unsigned char *mac, unsigned int len)
{
    (void)mac;
    (void)len;
    printf("\n<< ATTENTION !!! >> GetLocalAddr WEAK FUNC!!!\n");
    return true;
}

void D_GetBtMac(void)
{
    unsigned char addr[MAC_SIZE] = {0};
    if (!GetLocalAddr(addr, MAC_SIZE)) {
        Logf(ERROR, "GetLocalAddr fail");
        return;
    }
    Logf(INFO, "BT MAC - ["MAC_STR"]", MAC_ADDR(addr));
}

static char *GetCapValue(void)
{
    int32_t choice = GetInputNumber("The capability list show as below:\n"
        "0 - hicall \n"
        "1 - profile \n"
        "2 - homevisionPic \n"
        "3 - castPlus \n"
        "4 - aaCapability \n"
        "5 - dvKit \n"
        "6 - ddmpCapability \n"
        "7 - osdCapability (default) \n"
        "8 - share \n"
        "9 - approach \n"
        "Please input capability num: ");
    if (choice < 0 || choice > MAX_CAP_NUM) {
        Logf(INFO, ">>>The input num is invalid, use default: osdCapability");
        choice = DEFAULT_CAP_NUM;
    }
    return g_capabilityMap[choice].capability;
}

static sem_t g_publishSem;
static void OnPublishResult(int publishId, PublishResult reason)
{
    if (reason != PUBLISH_LNN_SUCCESS){
        Logf(INFO, ">>>publish failed: publishId=%d, result=%d", publishId, reason);
    } else {
        Logf(INFO, ">>>publish success: publishId=%d", publishId);
    }
    
    sem_post(&g_publishSem);
}

void D_PublishLNN(void)
{
    sem_init(&g_publishSem, 0, 0);
    PublishInfo info = {
        .publishId = 1024,
        .medium = AUTO,
        .mode = DISCOVER_MODE_ACTIVE,
        .freq = MID,
        .capability = "osdCapability",
        .capabilityData = NULL,
        .dataLen = 0,
        .ranging = false,
    };
    info.publishId = GetInputNumber("Please input publish id:");
    info.medium = GetInputNumber("Please input publish medium(0 - AUTO, 1 - BLE, 2 - COAP):");
    int32_t choice = GetInputNumber("Please input publish mode(0 - PASSIVE(default), 1 - ACTIVE):");
    info.mode = (choice == 1) ? DISCOVER_MODE_ACTIVE : DISCOVER_MODE_PASSIVE;
    choice = GetInputNumber("Please input publish ranging(0 - false(default), 1 - true):");
    info.ranging = (choice == 1) ? true : false;
    info.capability = GetCapValue();
    
    IPublishCb cb = {
        .OnPublishResult = OnPublishResult,
    };
    int ret = PublishLNN(PKG_NAME, &info, &cb);
    if (ret != 0) {
        Logf(ERROR, "PublishLNN fail, ret = %d", ret);
        sem_destroy(&g_publishSem);
        return;
    }
    sem_wait(&g_publishSem);
    sem_destroy(&g_publishSem);
}

void D_StopPublishLNN(void)
{
    int publishId = GetInputNumber("Please input publish id:");
    int ret = StopPublishLNN(PKG_NAME, publishId);
    if (ret != 0) {
        Logf(ERROR, "StopPublishLNN fail, ret = %d", ret);
    }
}

static sem_t g_refreshSem;
static bool g_showDevice = false;
static bool g_refreshSucc = false;
static void OnDiscoverResult(int refreshId, RefreshResult reason)
{
    if (reason != REFRESH_LNN_SUCCESS) {
        Logf(ERROR, ">>>RefreshLNN failed: refreshId=%d, result=%d", refreshId, reason);
    } else {
        Logf(INFO, ">>>RefreshLNN success: refreshId=%d", refreshId);
        g_refreshSucc = true;
    }
    sem_post(&g_refreshSem);
}

static void OnDeviceFound(const DeviceInfo *device)
{
    if (device == NULL || !g_showDevice) {
        printf("Device found but not show: device is null or no need to show\n");
        return;
    }

    uint32_t i = 0;
    while (i < device->addrNum) {
        switch (device->addr[i].type) {
            case CONNECTION_ADDR_BLE:
                Logf(INFO, ">>>OnDeviceFound: BLE MAC - %s | DevId - %s | DevName - %s | devType - %d | "
                    "isOnline - %s | Range - %d | CustData - %s",
                    device->addr[i].info.ble.bleMac, device->devId, device->devName, device->devType,
                    device->isOnline ? "true" : "false", device->range, device->custData);
                break;
            case CONNECTION_ADDR_BR:
                Logf(INFO, ">>>OnDeviceFound: BR MAC - %s | DevId - %s | DevName - %s | devType - %d | "
                    "isOnline - %s | Range - %d | CustData - %s",
                    device->addr[i].info.ble.bleMac, device->devId, device->devName, device->devType,
                    device->isOnline ? "true" : "false", device->range, device->custData);
                break;
            case CONNECTION_ADDR_ETH:
            case CONNECTION_ADDR_WLAN:
                Logf(INFO, ">>>OnDeviceFound: IP ADDR:Port - %s:%d | DevId - %s | DevName - %s | "
                    "devType - %d | isOnline - %s | CustData - %s",
                    device->addr[i].info.ip.ip, device->addr[i].info.ip.port, device->devId, device->devName,
                    device->devType, device->isOnline ? "true" : "false", device->custData);
                break;
            default:
                Logf(ERROR, ">>>OnDeviceFound: unknown device type, %d", device->addr[i].type);
                break;
        }
        i++;
    }
}

void D_RefreshLNN(void)
{
    sem_init(&g_refreshSem, 0, 0);
    SubscribeInfo info = {
        .subscribeId = 1024,
        .medium = AUTO,
        .mode = DISCOVER_MODE_ACTIVE,
        .freq = MID,
        .isSameAccount = false,
        .isWakeRemote = false,
        .capability = "osdCapability",
        .capabilityData = NULL,
        .dataLen = 0,
    };
    info.subscribeId = GetInputNumber("Please input subscribe id:");
    info.medium = GetInputNumber("Please input refresh medium(0 - AUTO, 1 - BLE, 2 - COAP):");
    int32_t choice = GetInputNumber("Please input refresh mode(0 - PASSIVE, 1 - ACTIVE(default)):");
    info.mode = (choice == 0) ? DISCOVER_MODE_PASSIVE : DISCOVER_MODE_ACTIVE;
    info.capability = GetCapValue();

    IRefreshCallback cb = {
        .OnDeviceFound = OnDeviceFound,
        .OnDiscoverResult = OnDiscoverResult,
    };
    
    g_showDevice = true;
    g_refreshSucc = false;
    int ret = RefreshLNN(PKG_NAME, &info, &cb);
    if (ret != 0) {
        printf("RefreshLNN fail, ret = %d.\n", ret);
        sem_destroy(&g_refreshSem);
        return;
    }
    sem_wait(&g_refreshSem);
    if (g_refreshSucc) {
        WaitInputEnter("Found Devices shown below, please input ENTER key to break.\n");
        g_showDevice = false;
    }
    sem_destroy(&g_refreshSem);
}

void D_StopRefreshLNN(void)
{
    int subscribeId = GetInputNumber("Please input subscribe id:");
    int ret = StopRefreshLNN(PKG_NAME, subscribeId);
    if (ret != 0) {
        Logf(ERROR, "StopRefreshLNN fail, ret = %d.\n", ret);
    }
}
